import {Jwt, TokenInfo} from '../types/auth'
import RedisClient from './redis'
import {DwPrismaClient} from './prisma'
import crypto from 'crypto'
import {tokenExpire} from './const'
import {StatusMap} from 'elysia'
import {updLoginLog} from './dw'

const key = 'dwyanewang'

/**
 * @description: crypto加密
 * @param {string} str 需加密的字符串
 * @param {string} salt1 密钥key
 * @param {string} salt2 加密向量iv
 */
export const encrypt = (str: string, salt1: string, salt2: string) => {
  const cipher = crypto.createCipheriv('aes-128-cbc', Buffer.from(salt1, 'hex'), Buffer.from(salt2, 'hex'))
  let sign = cipher.update(str + key, 'utf-8', 'hex')
  sign += cipher.final('hex')
  return sign
}

/**
 * @description: crypto解密
 * @param {string} str 加密后的字符串
 * @param {string} salt1 密钥key
 * @param {string} salt2 加密向量iv
 */
export const decrypt = (str: string, salt1: string, salt2: string) => {
  const cipher = crypto.createDecipheriv('aes-128-cbc', Buffer.from(salt1, 'hex'), Buffer.from(salt2, 'hex'))
  let sign = cipher.update(str, 'hex', 'utf-8')
  sign += cipher.final('utf-8')
  return sign.split(key)[0]
}

type AuthUser = {
  username: string
  id: number
  pSalt: string
}

/** 创建token */
export const createToken = async (jwt: Jwt, redis: RedisClient, user: AuthUser, roleIds: number[], expire = 'expire', isRefresh = false) => {
  const tokenInfo: TokenInfo = {
    isRefresh,
    roleIds,
    userId: user.id,
    username: user.username,
    sign: user.pSalt,
    timestamp: Date.now(),
  }
  const exp = tokenExpire[expire as keyof typeof tokenExpire]
  const token = await jwt.sign({...tokenInfo, exp})
  !isRefresh && (await redis.set(`user:token:${user.id}`, token, exp))
  return {expire: Date.now() + exp, token}
}

/** 删除token */
export const removeToken = async (prisma: DwPrismaClient, redis: RedisClient, id: number) => {
  await updLoginLog(prisma, {userId: id, online: 0})
  await redis.del(`user:sign:${id}`)
  await redis.del(`user:token:${id}`)
}

const wsOutline = [
  {
    code: 'outline',
    msg: '该账号已在其他设备上登录',
  },
  {
    code: 'outline-force',
    msg: '该账号已强制退出',
  },
]

export const getWSOutlineExcept = (params?: string) => {
  const _info = wsOutline.find(e => e.code === params)
  if (_info) throw new UnauthorizedError(_info.msg)
}

/** 判断是否为超管 */
export const isAdmin = async (prisma: DwPrismaClient, curUser?: TokenInfo) => {
  if (curUser && curUser.roleIds) {
    const _list = await prisma.role.findMany({
      where: {
        id: {
          in: curUser.roleIds,
        },
      },
      select: {
        name: true,
      },
    })
    return _list.filter(e => e.name === 'admin').length > 0
  }
  return false
}

/** 判断是否为当前登录用户 */
export const isSelf = (id: number, curUser?: TokenInfo) => curUser?.userId === id

export class DWError extends Error {
  status: number
  constructor(status: keyof StatusMap, message?: string) {
    super(message)
    this.status = StatusMap[status]
  }
}

export class UnauthorizedError extends DWError {
  constructor(message?: string) {
    super('Unauthorized', message)
  }
}

export class ForbiddenError extends DWError {
  constructor(message?: string) {
    super('Forbidden', message)
  }
}

export enum RESCODE {
  SUCCESS = 200, // 请求成功
  UNKNOWN = 400, // 未知错误
  PARSE = 400, // Bad Request 客户端请求的语法错误，服务器无法理解
  INVALID_COOKIE_SIGNATURE = 400, // Bad Request 客户端请求的语法错误，服务器无法理解
  UNAUTHORIZED = 401, //请求要求用户的身份认证
  FORBIDDEN = 403, //服务器理解请求客户端的请求，但是拒绝执行此请求
  NOT_FOUND = 404, //请求资源不存在
  VALIDATION = 422, //客户端传参校验错误
  INTERNAL_SERVER_ERROR = 500, // Internal Server Error 服务器内部错误，无法完成请求
}
